﻿// Basic component with no children
define([
'Xjs/core/util',
// Ensure the creation of the global Xjs
'Xjs/app'
],
function (util) {
    'use strict';

    var type = 'component',
    Component = Xjs.getType(type);

    if (Component) { // It has been already loaded
        return Component;
    }

    // Base component. It features id generation, type and instance registration
    Component = util.define({
        construct: function (conf, parent) {

            conf = conf || {};

            // The id of the component
            this.id = conf.id;

            // The parent component on this one, might be null in case of a root object
            this.parent = parent;

            // The required id is set in the following priority order
            var requiresId = conf.requiresId || this.requiresId,
            requiresRegistration = this.id ? true : false; // We assume that by providing a custom id, the user wants to access the component, therefore we register it

            if (requiresId) {
                this.ensureId();
            }

            if (requiresRegistration) {
                Xjs.register(this);
            }

            this.created = true; // Flag the component as created
        },

        ensureId: function () {
            if (!this.id) {
                if (this.generateId) {
                    this.id = this.generateId(); // Provide a custom id generation
                }
                else {
                    if (this.parent && this.parent.id) {
                        this.id = Xjs.generateId(this.parent.id + '_' + this.type);
                    }
                    else {
                        var branchId = this.getBranchId();

                        if (branchId == '') {
                            this.id = Xjs.generateId(this.type);
                        }
                        else {
                            this.id = Xjs.generateId(branchId + '_' + this.type);
                        }
                    }
                }
            }
        },

        // The type of the component
        type: type,

        // Whether an id must be generated if it is not provided
        requiresId: false,

        // Visits all the parents of the component
        up: function (callback, scope, excludeMe) {
            scope = scope || this;
            var fcn = util.isFunction(callback) ? callback : scope[callback];

            if (!excludeMe && fcn) {
                if (fcn.call(scope) === false) { // Returning false stops the traversal
                    return;
                }
            }

            if (this.parent) {
                this.parent.up(callback);
            }
        },

        getBranchId: function () {
            var parts = [];

            this.up(function () {
                if (this.id) {
                    parts.push(this.id);
                }
                else {
                    parts.push(this.type);
                }
            },
            this,
            true); // Exclude me

            return parts.reverse().join('_');
        },

        // Add handlers for specific events
        addHandler: function (evt, fcn) {
            if (!this.handlers) {
                this.handlers = {};
            }

            if (!this.handlers[evt]) {
                this.handlers[evt] = [];
            }

            this.handlers[evt].push(fcn);
        },

        callHandlers: function (evt) {
            if (!this.handlers) {
                return;
            }

            var handlers = this.handlers[evt];

            if (!handlers) {
                return;
            }

            var me = this;
            handlers.forEach(function (fcn) {
                fcn.call(me);
            });
        },

        toString: function () {
            return this.type + ' id:' + (this.id || '[not set]');
        },

        // Releases any resource taken by the component
        destroy: function () {

            if (this.handlers) {
                this.handlers = null;
            }

            // Remove the child of the registered ids if it was registered
            Xjs.remove(this);
        }
    });

    Xjs.registerType(Component);

    return Component;
});